<template>
    <div>
      <!-- 孙组件模板 -->
      <h3>孙组件</h3>
      <div class="attrs-content">
        <p>孙组件接收到的属性：</p>
        <p><strong>标题:</strong> {{ title }}</p>
        <p><strong>消息:</strong> {{ message }}</p>
        <p><strong>数量:</strong> {{ count }}</p>
        
        <p>其他透传属性:</p>
        <pre>{{ otherAttrsDisplay }}</pre>
        
        <button @click="triggerGrandsonEvent">从孙组件触发事件</button>
      </div>
    </div>
  </template>
  
  <script lang="ts" setup>
  /**
   * $attrs 详解 - 孙组件部分
   * 
   * 1. 多层级属性透传：
   *    - 通过 $attrs，可以实现属性从祖先组件直接传递到后代组件
   *    - 中间组件不需要声明或处理这些属性，只需要透传即可
   * 
   * 2. 属性合并：
   *    - 当多个组件传递相同属性时，后面的会覆盖前面的
   *    - 例如：父组件传递 title="A"，子组件传递 title="B"，孙组件会接收到 title="B"
   * 
   * 3. 事件冒泡：
   *    - 通过 $attrs 透传的事件处理函数可以在任何层级触发
   *    - 这使得深层嵌套的组件可以直接与顶层组件通信
   */
  
  import { computed, useAttrs } from 'vue';
  
  // 声明接收的 props
  const props = defineProps<{
    title: string;
    message: string;
    count: number;
  }>();

  const emit = defineEmits<{
    (e: 'custom-event', payload: any): void;
  }>();
  
  // 获取除了声明为 props 之外的其他属性
  const attrs = useAttrs();
  
  // 格式化其他属性用于显示
  const otherAttrsDisplay = computed(() => {
    // 过滤掉已经声明为 props 的属性
    const { title, message, count, ...otherAttrs } = attrs;
    return JSON.stringify(otherAttrs, null, 2);
  });
  
  // 触发事件（会冒泡到父组件和祖父组件）
  function triggerGrandsonEvent() {
    console.log('孙组件触发事件');
    console.log(attrs['onCustom-event'] )
    // 使用从 $attrs 中获取的事件处理函数
      emit('custom-event', {
        from: '孙组件',
        text: '孙组件触发的事件',
        time: new Date().toLocaleTimeString()
    });
  }
  
  /**
   * 4. $attrs 的应用场景：
   *    4.1 组件库开发：创建高度可定制的组件
   *    4.2 HOC (高阶组件)：包装现有组件并保留其所有功能
   *    4.3 深层组件通信：避免 props 逐层传递的繁琐
   *    4.4 动态组件：根据不同条件渲染不同组件但保持相同的属性
   * 
   * 5. 最佳实践：
   *    5.1 明确文档说明组件接收哪些属性和事件
   *    5.2 避免过度依赖 $attrs，适当时使用 props 和 emits 声明
   *    5.3 使用 TypeScript 类型增强类型安全
   *    5.4 在透传属性时考虑是否需要修改或过滤某些属性
   */
  </script>
  
  <style scoped>
  /* 孙组件样式 */
  div {
    background: linear-gradient(to right, #43cea2, #185a9d);
    border-radius: 12px;
    padding: 20px;
    margin: 15px 0;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    transition: all 0.3s ease;
  }
  
  div:hover {
    transform: translateY(-5px);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  }
  
  h3 {
    color: #ffffff;
    font-size: 22px;
    margin-bottom: 15px;
    text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
    font-weight: 500;
    letter-spacing: 1px;
  }

  .attrs-content {
    background-color: rgba(255, 255, 255, 0.2);
    border-radius: 8px;
    padding: 15px;
  }

  p {
    margin: 8px 0;
    color: white;
  }

  pre {
    background-color: rgba(0, 0, 0, 0.1);
    padding: 10px;
    border-radius: 5px;
    color: white;
    font-family: monospace;
    overflow-x: auto;
    margin: 10px 0;
  }

  button {
    background-color: white;
    color: #185a9d;
    border: none;
    padding: 8px 15px;
    border-radius: 6px;
    font-weight: bold;
    cursor: pointer;
    margin-top: 10px;
    transition: all 0.2s;
  }

  button:hover {
    background-color: #185a9d;
    color: white;
  }
  </style>